#-------------------------------------------------------------------------------
# Copyright (c) 2012 Huseyin BIYIK.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the GNU Public License v3.0
# which accompanies this distribution, and is available at
# http://www.gnu.org/licenses/gpl.html
# 
# Contributors:
#     Huseyin BIYIK - initial API and implementation
#-------------------------------------------------------------------------------
import pyaudio, audioop, Queue, threading, binascii, time
from defs import *

class audio_interface(threading.Thread):
	def __init__(self, identifier, outfunc):
		threading.Thread.__init__(self)
		self.is_closing = False
		self.active = False
		self.identifier = identifier
		self.readbuf = ""
		self.writebuf = ""
		self.codec = codec()
		self.outfunc = outfunc
		try:
			self.p = pyaudio.PyAudio()
			self.stream_r = self.p.open(format=pyaudio.paInt16, channels=1, rate=8000, input=True, output=False, frames_per_buffer=1024)
			self.stream_w = self.p.open(format=pyaudio.paInt16, channels=1, rate=8000, input=False, output=True, frames_per_buffer=1024)
			#print self.p.get_default_host_api_info()
			print self.p.get_host_api_info_by_type(pyaudio.paMME)
		except IOError, e:
			logger.error("Audio interface can not be initialized :  %s" , e)
			return None
		logger.info("Audio interface initialized")
		self.start()
			
	def close(self):
		self.is_closing = True
		try:
			self.stream_w.close()
			self.stream_r.close()
		except IOError, e:
			logger.error("Audio interface can not be closed :  %s retrying" , e)
			self.close()
		threading.Thread.join(self)
		return True

	def run(self):
		bite = (udp_packet_size - max_header) * 2
		t1 = 0
		while 1:
			chunk = self.stream_r.get_read_available()
			if (not self.is_closing) and chunk and self.active:
				try:
					self.readbuf += self.stream_r.read(chunk)
					while len(self.readbuf) > bite:
						payloadbuf = self.readbuf[:bite]
						self.readbuf = self.readbuf[bite:]
						payload = self.codec.compress(payloadbuf)
						diff = (time.time() - t1)
						if diff > 0:
							print "audio read speed--------------------------(" + str(int(len(payload) / diff / 1000)) + ")-----------------"
						self.outfunc(self.identifier, "audio", payload)
						t1 = time.time()

				except IOError, e:
					logger.error("Audio interface cant read stream: %s", e)
					continue
			elif self.is_closing:
				return

	def write(self, payload):
		self.writebuf += payload
		if len(self.writebuf) < 2048:	
			return
		while 1:
			if len(self.writebuf) % 2 != 0:
				swap = -1
			else:
				swap = -2
			audio = self.codec.decompress(self.writebuf[:swap])
			self.writebuf = self.writebuf[swap:]
			try:
				self.stream_w.write(audio)
			except IOError, e:
				logger.error("Audio interface cant write %d byte to stream: %s", asciisize(audio), e)
				return False
			if len(self.writebuf) < 10:
				return True


class codec():
	def __init__(self):
		logger.info("Codecs initialized")
	def compress(self, audio):
		try:
			return audioop.lin2ulaw(audio, 2)
		except audioop.error, e:
			logger.error("Codec cant encode %d byte aduio : %s", asciisize(audio), e)
			return ""
	
	def decompress(self, payload):
		try:
			return audioop.ulaw2lin(payload, 2)
		except audioop.error, e:
			logger.error("Codec cant decode %d byte aduio : %s", asciisize(payload), e)
#			hex=binascii.hexlify(payload)
#			print str(len(hex)/2)+ " : " + str(hex)
#			print binascii.hexlify(payload[-1:])
			return ""
